package com.nageoffer.shortlink.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nageoffer.shortlink.admin.dao.entity.Group;
import com.nageoffer.shortlink.admin.dao.mapper.GroupMapper;
import com.nageoffer.shortlink.common.dto.admin.req.GroupCreateReqDTO;
import com.nageoffer.shortlink.common.dto.admin.req.GroupSortReqDTO;
import com.nageoffer.shortlink.common.dto.admin.req.GroupUpdateReqDTO;
import com.nageoffer.shortlink.common.dto.admin.resp.GroupGetRespDTO;
import com.nageoffer.shortlink.admin.service.GroupService;
import com.nageoffer.shortlink.common.constant.RedisConstant;
import com.nageoffer.shortlink.common.convention.exception.ClientException;
import com.nageoffer.shortlink.common.convention.result.Result;
import com.nageoffer.shortlink.common.dto.admin.biz.UserContext;
import com.nageoffer.shortlink.common.utils.RandomGenerator;
import com.nageoffer.shortlink.remote.ShortLinkClient;
import com.nageoffer.shortlink.common.dto.project.resp.ShortLinkGroupCountRespDTO;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Service
@RequiredArgsConstructor
public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements GroupService {
    private final ShortLinkClient shortLinkClient;
    private final RedissonClient redissonClient;
    @Value("${short-link.group.max-num}")
    private Integer groupMaxNum;
    @Override
    public void saveGroup(GroupCreateReqDTO requestParam) {
        saveGroup(requestParam.getName(),UserContext.getUsername());
    }
    @Override
    public void saveGroup(String name, String username) {
        RLock lock = redissonClient.getLock(RedisConstant.LOCK_GROUP_CREATE_KEY + username);
        lock.lock();
        try{
            List<Group> groups = lambdaQuery().eq(Group::getUsername, username)
                    .eq(Group::getDelFlag, 0)
                    .list();
            if (CollUtil.isNotEmpty(groups) && groups.size()==groupMaxNum) {
                throw new ClientException(String.format("超出最大分组数:%d",groupMaxNum));
            }
            String gid;
            do {
                gid = RandomGenerator.generateRandomCode(6);
            } while (hasGid(gid,username));
            Group group = Group.builder()
                    .gid(gid)
                    .username(username)
                    .name(name)
                    .build();
            save(group);
        }finally {
            lock.unlock();
        }
    }

    @Override
    public List<GroupGetRespDTO> getGroups() {
        String username = UserContext.getUsername();
        List<Group> groups = lambdaQuery()
                .eq(Group::getUsername, username)
                .eq(Group::getDelFlag,0)
                .orderByDesc(Group::getSortOrder,Group::getUpdateTime)
                .list();
        List<GroupGetRespDTO> groupDTOs = BeanUtil.copyToList(groups, GroupGetRespDTO.class);
        List<String> ids = groups.stream().map(Group::getGid).toList();
        Result<List<ShortLinkGroupCountRespDTO>> listResult = shortLinkClient
                .groupShortLinkCount(ids);
        groupDTOs.forEach(each->{
            Optional<ShortLinkGroupCountRespDTO> gidMatch = listResult.getData().stream()
                    .filter(item -> Objects.equals(item.getGid(), each.getGid()))
                    .findFirst();
            gidMatch.ifPresent(item->each.setShortLinkCount(item.getShortLinkCount()));
        });
        return groupDTOs;
    }
    @Override
    public List<Group> getSimpleGroups() {
        String username = UserContext.getUsername();
        return lambdaQuery()
                .eq(Group::getUsername, username)
                .eq(Group::getDelFlag,0)
                .list();
    }

    @Override
    public void updateGroup(GroupUpdateReqDTO requestParam) {
        lambdaUpdate()
                .eq(Group::getUsername,UserContext.getUsername())
                .eq(Group::getGid,requestParam.getGid())
                .set(Group::getName,requestParam.getName())
                .update();
    }

    @Override
    public void deleteGroup(String gid) {
        lambdaUpdate()
                .eq(Group::getUsername,UserContext.getUsername())
                .eq(Group::getGid,gid)
                .set(Group::getDelFlag,1)
                .update();
    }

    @Override
    public void sortGroup(List<GroupSortReqDTO> requestParam) {
        requestParam.forEach(each->{
            lambdaUpdate()
                    .eq(Group::getUsername,UserContext.getUsername())
                    .eq(Group::getGid,each.getGid())
                    .eq(Group::getDelFlag,0)
                    .update(BeanUtil.copyProperties(each,Group.class));
        });
    }

    public boolean hasGid(String gid,String username){
        Group group = lambdaQuery()
                .eq(Group::getGid, gid)
                .eq(Group::getUsername, username)
                .one();
        return group!=null;
    }

}
